package cz.muni.fi.pa165.travelagency.persistence;

import cz.muni.fi.pa165.travelagency.api.entities.IOrder;
import cz.muni.fi.pa165.travelagency.entities.PackageTour;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 * @author Lukas Jungmann
 * @version 1.0
 */
@Stateless
public class PackageTourDAO implements IPackageTourDAO {

    @PersistenceContext(unitName = "LivePU")
    private EntityManager em;

    public PackageTourDAO() {
    }

    /**
     * mainly for tests
     *
     * @param em
     */
    void setEntityManager(EntityManager em) {
        if (em == null) {
            throw new IllegalArgumentException("EntityManager is null.");
        }
        this.em = em;
    }

    @Override
    public void createPackageTour(PackageTour pt) {
        if (pt.getId() != null) {
            throw new IllegalStateException("unmanaged PackageTour");
        }
        if (pt.getCapacity() < 1) {
            throw new IllegalArgumentException("capacity must be greater then zero");
        }
        if (pt.getName() == null) {
            throw new IllegalArgumentException("name cannot be null");
        }
        if (pt.getDescription() == null) {
            throw new IllegalArgumentException("description cannot be null");
        }
        if (pt.getDestination() == null) {
            throw new IllegalArgumentException("destination cannot be null");
        }
        if (pt.getEnd() == null) {
            throw new IllegalArgumentException("endDate cannot be null");
        }
        if (pt.getStart() == null) {
            throw new IllegalArgumentException("startDate cannot be null");
        }
        if (pt.getPricePerPerson() == null) {
            throw new IllegalArgumentException("pricePerPerson cannot be null");
        }
        if (pt.getPricePerPerson().intValue() < 0) {
            throw new IllegalArgumentException("pricePerPerson cannot be less then zero");
        }
        if (pt.getStart().after(pt.getEnd())) {
            throw new IllegalArgumentException("startDate must be before endDate");
        }
        persist(pt);
    }

    @Override
    public void deletePackageTour(PackageTour pt) {
        if (pt == null) {
            throw new IllegalArgumentException("PackageTour (pt) cannot be null");
        }
        if (pt.getId() == null) {
            throw new IllegalStateException("ID cannot be null");
        }
        delete(pt.getId());
    }

    @Override
    public List<PackageTour> findAll() {
        try {
            return em.createNamedQuery("PackageTour.findAll").getResultList();
        } catch (Throwable t) {
            throw new DAOException(t.getMessage(), t);
        }
    }

    private PackageTour findByID(Long id) {
        List<PackageTour> result = findBy("PackageTour.findById", "id", id);
        return result != null && result.size() > 0 ? result.get(0) : null;
    }

    @Override
    public int getAvailablePlaces(PackageTour pt) {
        if (pt == null) {
            throw new IllegalArgumentException("pt cannot be null");
        }
        int freePlaces = findByID(pt.getId()).getCapacity();
        for (IOrder o : pt.getOrders()) {
            if (pt.equals(o.getOrderedPackageTour())) {
                freePlaces -= o.getNumberOfPersons();
            }
        }
        return freePlaces;
    }

    @Override
    public PackageTour getPackageTour(Long id) {
        if (id == null) {
            throw new IllegalArgumentException("id cannot be null");
        }
        if (id < 1) {
            throw new IllegalArgumentException("id must be grater then zero");
        }
        return findByID(id);
    }

    @Override
    public void updatePackageTour(PackageTour pt) {
        if (pt == null) {
            throw new IllegalArgumentException("pt cannot be null");
        }
        if (pt.getId() == null) {
            throw new IllegalStateException("unmanaged PackageTour (pt.id is null)");
        }
        try {
            em.merge(pt);
        } catch (Throwable t) {
            throw new DAOException(t.getMessage(), t);
        }
    }

    private synchronized void persist(Object object) {
        try {
            em.persist(object);
        } catch (Throwable t) {
            throw new DAOException(t.getMessage(), t);
        }
    }

    private synchronized void delete(Long id) {
        try {
            PackageTour pt = em.find(PackageTour.class, id);
            if (pt != null) {
                em.remove(pt);
            }
        } catch (Throwable t) {
            throw new DAOException(t.getMessage(), t);
        }

    }

    private List<PackageTour> findBy(String queryName, String attrName, Object attrValue) {
        try {
            Query q = em.createNamedQuery(queryName);
            q.setParameter(attrName, attrValue);
            return q.getResultList();
        } catch (Throwable t) {
            throw new DAOException(t.getMessage(), t);
        }

    }

    @Override
    public List<PackageTour> find(String destination, int maxPrice, Date dateFrom, Date dateTo, int numberOfPersons) {
        try {
            Query q = em.createNamedQuery("PackageTour.findByAttributes");
            q.setParameter("start", dateFrom);
            q.setParameter("end", dateTo);
            q.setParameter("maxPrice", new BigDecimal(maxPrice));
            q.setParameter("destination", "%" + destination + "%");
            q.setParameter("capacity", numberOfPersons);
            return q.getResultList();
        } catch (Throwable t) {
            throw new DAOException(t.getMessage(), t);
        }
    }
}
